until now, Punctuation chords providing leader (Space / Enter) capitalization shortcuts, lengthened the hold of the punctuation key which adds a subtle disruption to the typing rhythm— much like traditional shifting.
Introducing the rolling key logic for rapid finger rolls makes these chords feel much more natural, especially as finger memory of these simple chords becomes ingrained, their beauty providing one shot capitalization for any letter following a Space or Enter leader—a majority of capitalizations. Once mastered, traditional shift-letter capitalization becomes a thing of the past..
Tap key actions with Punctuation* key down for..
keycode | single tap | double tap |
---|---|---|
Space | Punctuation* Space Shift | … |
Enter | Punctuation* Enter Shift | Punctuation* Enter Enter Shift |
*Where “Punctuation” is (Shift), Period, Comma, Colon, Semicolon, Question or Exclamation Mark. Shift-Space/Enter simply auto-capitalizes after the Space or Enter. (Backspace cancels the one shot modifier.)
Refer to the beaklpi source files for the following..
as before, the leadercap auto-capitalization flag is passed as an external state flag (versus a function parameter), as only select punctuation keys trigger leader capitalization..
static uint8_t leadercap = 0;
bool process_record_user(uint16_t keycode, keyrecord_t *record)
{
switch (keycode) {
case HOME_A:
leadercap = KEY_DOWN ? 1 : 0;
mod_roll(record, LEFT, SHIFT, KC_LSFT, KC_A, 3);
break;
...
the leader keys, Space and Enter, previously unmanaged by the mod_roll function, are now added as columns 10 and 11 to distinguish them from the finger cluster columns of the rolling matrix table..
...
case LT_ENT:
togglelayer = _EDIT;
if (mod_roll(record, RIGHT, NOSHIFT, 0, KC_ENT, 10)) { return false; }
break;
case KC_ENT:
if (mod_roll(record, RIGHT, NOSHIFT, 0, KC_ENT, 10)) { return false; }
break;
case LT_SPC:
togglelayer = _SYMGUI;
if (mod_roll(record, RIGHT, NOSHIFT, 0, KC_SPC, 11)) { return false; }
break;
the BEAKL layout variants on this site are unique in the shift mapping of punctuation keys on the base layer (Dot -> Question Mark, Comma -> Exclamation Mark and Colon -> Semicolon). These keys are now added to the rolling matrix table..
...
case KC_COLN:
leadercap = KEY_DOWN ? 1 : 0;
if (map_roll(record, LEFT, KC_RSFT, NOSHIFT, KC_COLN, 4)) { return false; }
break;
case TD_COLN:
leadercap = KEY_DOWN ? 1 : 0;
if (map_roll(record, LEFT, KC_RSFT, NOSHIFT, KC_COLN, 4)) { return false; }
break;
case KC_COMM:
leadercap = KEY_DOWN ? 1 : 0;
if (map_roll(record, LEFT, KC_RSFT, SHIFT, KC_1, 4)) { return false; }
break;
case KC_DOT:
leadercap = KEY_DOWN ? 1 : 0;
if (map_roll(record, LEFT, KC_RSFT, SHIFT, KC_SLSH, 4)) { return false; }
break;
the rolling matrix table is enlarged for the added leader key columns and the leadercap variable state..
#define SET_EVENT(c) e[c].key_timer = timer_read(); e[c].keycode = keycode; e[c].shift = shift; e[c].side = side; e[c].leadercap = leadercap; prev_key = next_key; next_key = c
static struct column_event {
uint16_t key_timer;
uint16_t keycode;
uint8_t shift;
uint8_t side;
uint8_t leadercap;
} e[12];
the mod_roll() function is augmented with the leadercap state and issues one shot capitalization accordingly for the leader key..
#define ROLL(s, k) ((s == LEFT) && e[RSHIFT].shift) || ((s == RIGHT) && e[LSHIFT].shift) ? tap_shift(k) : tap_key(k)
static uint8_t togglelayer = 0;
bool mod_roll(keyrecord_t *record, uint8_t side, uint8_t shift, uint16_t modifier, uint16_t keycode, uint8_t column)
{
if (KEY_DOWN) {
...
} else {
...
if (timer_elapsed(e[column].key_timer) < TAPPING_TERM) {
if (e[column].key_timer < e[next_key].key_timer) {
...
} else { ROLL(side, keycode); e[prev_key].key_timer = 0; e[column].leadercap = 0; }
}
if (e[prev_key].leadercap && (column >= 10)) {
if (togglelayer) { layer_off(togglelayer); togglelayer = 0; }
layer_on (_SHIFT);
set_oneshot_layer(_SHIFT, ONESHOT_START);
e[prev_key].leadercap = 0;
return true;
}
...
}
return false;
}
the map_roll() function is a rolling matrix table (leadercap) wrapper for the map_shift function..
bool map_roll(keyrecord_t *record, uint8_t side, uint16_t shift_key, uint8_t shift, uint16_t keycode, uint8_t column)
{
if (KEY_DOWN) { SET_EVENT(column); }
else { e[column].leadercap = 0; }
return map_shift(record, shift_key, shift, keycode);
}
the thumb I was originally omitted the rolling matrix table. To add for completeness for rolling capital I, the LT macro must be replaced with the MO layer toggle macro..
#define LT_I MO(_REGEX)
bool process_record_user(uint16_t keycode, keyrecord_t *record)
{
...
case LT_I:
if (map_shift(record, KC_LSFT, NOSHIFT, KC_SPC)) { return false; }
mod_roll(record, LEFT, NOSHIFT, 0, KC_I, 4);
break;
It is unnecessary to assign a unique column number to this thumb key. Reusing column 4 which aligns with the index finger reach position is sufficient. MO combined with mod_roll produces the equivalent LT macro result.
Presto! finger rolls are now consistently handled across the board for normal typing and leader capitalization.